iT邦幫忙

2021 iThome 鐵人賽

DAY 17
0
Modern Web

快搭上姐姐的`微`前端便車系列 第 17

第17車廂-超實用!tab頁籤切換:data-*應用篇

  • 分享至 

  • xImage
  •  

本篇介紹常用的tab切換功能,使用js、jq、Vue3如何做到,以及說明若一個版面會出現一個以上需要切換時,該注意什麼?

還記的我們在<第15車廂-data-*的坑?data-*介紹篇>,已經介紹了抓去data-*的用法,接著我們就要透過data-*來實作時常用的tab切換功能囉!(畫面陽春版喔)

▼ 完成圖

HTML

注意 data-tablink="*"的內容是對應下方tab內容的id="*"

<div class="tab-demo">
  <!-- tab標籤列 -->
  <ul class="tab-title">
    <li class="active">
      <a href="javascript:;" data-tablink="one">tab1</a>
    </li>
    <li>
      <a href="javascript:;" data-tablink="two">tab2</a>
    </li>
    <li>
      <a href="javascript:;" data-tablink="three">tab3</a>
    </li>
  </ul>
  <!-- tab內容 -->
  <div class="tab-inner-wrap">
    <div id="one" class="tab-inner">
      <!-- tab1的內容 -->
      內容1 內容1 內容1 內容1
    </div>
    <div id="two" class="tab-inner">
      <!-- tab2的內容 -->
       內容2
    </div>
    <div id="three" class="tab-inner">
      <!-- tab3的內容 -->
       內容3
    </div>
  </div>
</div>

...第二組

CSS

注意 li > a 原本是灰色li.active> a 則是加上藍色

.tab-demo {
  padding: 20px;
}

.tab-title {
  display: flex; // 將li 排列再一起
}

.tab-title li {
  padding: 10px;
}

.tab-title li a {
  display: block;
  padding: 10px;
  color: #333;
  background-color: #ccc;
  text-decoration: none;
}

.tab-title li.active a {
  color: #fff;
  background-color: #0071bc;
}

.tab-inner {
  padding: 10px;
  border: 1px solid #ccc;
}

引入JQ

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

JQ(錯誤版)

目標:需做到按到哪個li就秀出對應的內容
siblings() 是返回被選元素的所有同級元素。

$(document).ready(function () {
  tabCutover1();
});

function tabCutover1() {
  //抓出li.active的data-tablink的內容;例如是"one"
  var tablink = $(".tab-title li.active").find("a").data("tablink");
  
  //將$("#one").顯示,而其他兄弟們(叫做.tab-inner)都隱藏
  $('#'+ tablink).show().siblings(".tab-inner").hide();
  
  //當tab標題li被點到時,
  $(".tab-title li").click(function () {
      //抓出當下被點到的data-tablink的內容;例如是"Two",將$("#Two").顯示,而其他兄弟們(叫做.tab-inner)都隱藏
    $('#'+$(this).find("a").data("tablink")).show().siblings(".tab-inner").hide();
    //抓出當下被點到的li要加上active(藍色),其他li則要刪除active(藍色)
    $(this).addClass("active").siblings(".active").removeClass("active");
  });
}

▲好我們先停一下,看一下上方的code

看起來好像沒問題?但是呢,發現第1個tab畫面正常,第2個畫面tab內容卻都沒隱藏了,這是為什麼呢?
https://ithelp.ithome.com.tw/upload/images/20211002/20142016TwwNZlvLf1.png
主要因為,

  • $(".tab-title li.active").find("a").data("tablink");只能叫出符合的第一個
  • $(".tab-title li.active")元素目前有2個才對
  • 所以我們要改為each使用迴圈方式,這樣兩個選到的都能叫出來
    https://ithelp.ithome.com.tw/upload/images/20211002/20142016Low2jSsQXy.jpg
    所以呢,正如文章起頭提到,如果要一個版面有很多切換區域,就可以寫成下列寫法

JQ (正確共用版)

/*tab 收合*/
function tabCutover() {

 $(".tab-title li.active").each(function () {
    var tablink = $(this).find("a").data("tablink");

    $('#'+tablink).show().siblings(".tab-inner").hide();
  });

 $(".tab-title li").click(function () {
    $('#'+$(this).find("a").data("tablink")).show().siblings(".tab-inner").hide();
    $(this).addClass("active").siblings(".active").removeClass("active");
  });
}

這樣就解決啦!

JQ程式碼

附上JQ版切換程式碼

那...我們以上面邏輯用JS寫寫看(也太難寫了吧!)

HTML及CSS同上喔

JS(獻醜版)

我好像是第一次改寫JS...JS找節點實在不是很熟
▼ 主要是因為JS沒有siblings()找兄弟功能,要寫可能要寫很長,所以我只好寫成先叫大家都清除,在叫點出來的串供!
JS

const tabTitle = document.querySelectorAll(".tab-title li");
const tabInner = document.querySelectorAll(".tab-inner");

//tab內容大家都清除
tabInner.forEach(function (item) {
  item.style.display = "none";
});

//所有tab區域是active 抓出他data-tablink後 例如是"one" 就可以指定document.getElementById("one")將tab內容顯示
document.querySelectorAll(".tab-title li.active").forEach(function (item) {
  let tablink = item.querySelector("a").getAttribute("data-tablink");
  document.getElementById(tablink).style.display = "block";
});

//tab-title每個li做監聽 當click時
tabTitle.forEach(function (item) {
  item.addEventListener("click", function () {
    //抓出click那個元素的a的tablink,例如是"two"
    let tablink = item.querySelector("a").getAttribute("data-tablink");

    //先找到該父層將所有子層li 移除active的classname(藍色)
    item.parentNode.querySelectorAll("li").forEach(function (item) {
      item.classList.remove("active");
    });
    //在將click那個li加回active的classname(藍色)
    item.classList.add("active");
    //將剛剛抓出來的,例如是"two" >document.getElementById("two")的父層 <div class="tab_inner_wrap">...底下的tab內容都隱藏
    document.getElementById(tablink).parentNode.querySelectorAll(".tab-inner").forEach(function (item) {
        item.style.display = "none";
      });
    //因為剛剛是做全部底下的tab內容都隱藏,所以要再將剛剛抓出來的,例如是"two" tab內容秀出來
    document.getElementById(tablink).style.display = "block";
  });
});

程式碼JS

附上JS切換程式碼

那...我們加碼分享Vue3版本

Vue3(超超新手版)

最近剛好要練Vue,請看我超新手寫法XD

引入

<script src="https://unpkg.com/vue@next"></script>

HTML

  • 動態綁定classname 所以寫成:class 如果tabID是one的話就會有active這個class出現
  • li 發生click事件時 所以寫成@click 並將id當參數傳進去 去改變tabID
<div id="app">
  <div class="tab-demo">
    <!-- tab標籤列 -->
    <ul class="tab-title">
      <li :class="{ 'active': tabID == 'one'}"  @click="changeTab('one')">
        <a href="javascript:;" data-tablink="one">tab1</a>
      </li>
      <li  :class="{ 'active': tabID == 'two'}"  @click="changeTab('two')">
        <a href="javascript:;" data-tablink="two">tab2</a>
      </li>
      <li  :class="{ 'active': tabID == 'three'}" @click="changeTab('three')">
        <a href="javascript:;" data-tablink="three">tab3</a>
      </li>
    </ul>
    <!-- tab內容 -->
    <div class="tab-inner-wrap">
      <div id="one" class="tab-inner" v-if="tabID == 'one'">
        <!-- tab1的內容 -->
        內容1 內容1 內容1 內容1
      </div>
      <div id="two" class="tab-inner" v-if="tabID == 'two'">
        <!-- tab2的內容 -->
        內容2
      </div>
      <div id="three" class="tab-inner" v-if="tabID == 'three'">
        <!-- tab3的內容 -->
        內容3
      </div>
    </div>
  </div>
</div>

CSS同上喔

程式

const app = Vue.createApp({
  data(){
    return{
      tabID:'one',
    }
  },
  methods:{
    changeTab(id){
      this.tabID = id;
    }
  }
}).mount('#app')

程式碼Vue3

附上程式碼

本篇參考文章:
https://www.webdesigns.com.tw/jquery_tab.asp


上一篇
第16車廂-提示我一下嘛!bootstrap-tooltip應用篇
下一篇
第18車廂-動ㄘ動ㄘ!tab頁籤切換+輪播應用篇
系列文
快搭上姐姐的`微`前端便車30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言